/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using System.Qizx.Api;
using DataModelException = System.Qizx.Api.DataModelException;
using Node = System.Qizx.Api.Node;
using QName = System.Qizx.Api.QName;
using NamespaceContext = System.Qizx.Util.NamespaceContext;
using System.Qizx.XQuery.Op;

namespace System.Qizx.Xdm {

    public class BaseNodeFilter : NodeFilter {
        virtual public XdmNodeType NodeKind {
            get {
                return kind;
            }

        }
        public int srcLocation;

        /// <summary> Tested kind (ELEMENT TEXT PI COMMENT..., or -1 for node())</summary>
        public XdmNodeType kind; // 

        /// <summary> Namespace test: null if not specified (* or *:NCName)</summary>
        public string namespaceURI;

        /// <summary> Localname test: null if not specified (* or ns:*)</summary>
        public string name;

        /// <summary> Accelerator, non-null if non-null namespace and name.</summary>
        public QName qname;

        /**
     * Basetype for value: accepts only untypedAtomic in absence of Schema.
     */
        public SchemaContext schemaType;

        /// <summary>
        /// Builds a node test specifying the node-kind and optionally the name of
        /// nodes to match.
        /// </summary>
        /// <param name="kind">the node-kind as defined in Node: ELEMENT, ATTRIBUTE, TEXT
        /// etc.</param>
        /// <param name="namespaceURI">of the node name. If null, represents the wildcard
        /// *:NCName.</param>
        /// <param name="name">local part of node name. If null, represents the wildcard
        /// ns:* or *.</param>
        public BaseNodeFilter(XdmNodeType kind, string namespaceURI, string name) {
            this.kind = kind;
            this.namespaceURI = (namespaceURI == null) ? null : NamespaceContext.unique(namespaceURI);
            if (name != null)
                name = NamespaceContext.unique(name);
            this.name = name;
            if (namespaceURI != null && name != null)
                qname = IQName.GetQName(namespaceURI, name);
        }

        public BaseNodeFilter(XdmNodeType kind, String nsURI, String name,
                          SchemaContext schemaType)
            : this(kind, nsURI, name) {

            this.schemaType = schemaType;
        }

        public override string ToString() {
            return "baseNodeTest(" + kind + ", " + namespaceURI + ":" + name + ")";
        }

        /// <summary>
        /// Returns true for simple node test (node kind only).
        /// </summary>
        /// <returns></returns>
        public virtual bool StaticallyCheckable() {
            return namespaceURI == null && name == null;
        }

        public virtual bool Accepts(XdmNodeType nodeKind, QName nodeName) {
            if (kind > 0 && kind != nodeKind)
                return false;
            if (nodeName == null)
                // contract of the method
                return true;
            if (namespaceURI == null && name == null)
                // dont care about name
                return true;
            if (qname != null)
                // simple name
                return qname == nodeName;
            // nodeName cannot be null
            if (namespaceURI != null) {
                string nsuri = nodeName.Namespace;
                return (System.Object)namespaceURI == (System.Object)nsuri || namespaceURI.Equals(nsuri);
            }
                // Use of == is intentional:
            else
                return (System.Object)name == (System.Object)nodeName.Name;
        }

        public virtual bool NeedsNode() {
            return false;
        }

        public virtual bool Accepts(Node node) {
            try {
                if (schemaType == null || !schemaType.SchemaKindTest) {
                    if (!Accepts(node.NodeType, node.NodeName)) {
                        return false;
                    }
                    return schemaType == null || schemaType.acceptsNode(node);
                } else { //CoShare schema-element
                    if (kind > 0 && kind != node.NodeType)
                        return false;

                    return schemaType == null || schemaType.acceptsNode(node);
                }
            } catch (DataModelException e) {
                return false;
            }
        }
    }
}